﻿using HPSocket;
using HPSocket.Base;
using HPSocket.Tcp;
using Newtonsoft.Json;
using System;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace csharp_networkprotocol_hpsocket
{
    public partial class TCPServerOld : Form
    {
        /// <summary>
        /// HPSocket_TCPServer示例帮助类（示例学习）
        /// </summary>
        public HPSocket_TCPServerHelper _HPSocket_TCPServerHelper = new HPSocket_TCPServerHelper();

        /// <summary>
        /// 包数据结束符
        /// </summary>
        private readonly string _endsWith = "\r\n";

        public TCPServerOld()
        {
            InitializeComponent();
        }
        private void TCPServerOld_Load(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// 打开或关闭TCP
        /// </summary>
        private async void btnOpenCloseTCP_Click(object sender, EventArgs e)
        {
            try
            {
                if (btnOpenCloseTCP.Text == "开启监听")  // 开启监听
                {
                    // 检查地址
                    if (!CheckServerUrl())
                    {
                        return;
                    }

                    string localAddr = txtIPAddress.Text.Trim();  //IPAddress localAddr = IPAddress.Parse(txtIPAddress.Text.Trim());  // IP
                    int port = int.Parse(txtPort.Text);  // 端口

                    if (_HPSocket_TCPServerHelper._server == null || _HPSocket_TCPServerHelper.State != ServiceState.Started)
                    {
                        // <1>创建TCPServer对象
                        _HPSocket_TCPServerHelper.CreateTcpServer();  // 创建TcpServer
                        // <2>配置TCPServer的参数
                        _HPSocket_TCPServerHelper.Address = localAddr;      // IP
                        _HPSocket_TCPServerHelper.Port = (ushort)port;      // 端口
                        _HPSocket_TCPServerHelper.SocketBufferSize = 4096;  // 缓存4K
                        // <3>配置TCPServer的回调事件
                        _HPSocket_TCPServerHelper._server.OnAccept += OnAccept;                // TCP连接准备事件-使用附加数据处理黏包
                        _HPSocket_TCPServerHelper._server.OnHandShake += OnHandShake;          // TCP握手成功事件
                        _HPSocket_TCPServerHelper._server.OnPrepareListen += OnPrepareListen;  // 监听事件
                        _HPSocket_TCPServerHelper._server.OnSend += OnSend;                    // 数据包发送事件
                        _HPSocket_TCPServerHelper._server.OnReceive += OnReceive;              // 数据包接收事件
                        _HPSocket_TCPServerHelper._server.OnClose += OnClose;                  // TCP连接关闭事件
                        _HPSocket_TCPServerHelper._server.OnShutdown += OnShutdown;            // TCP服务器关闭事件
                    }
                    // <4>开启TCPServer服务
                    if (_HPSocket_TCPServerHelper.Start())
                    {
                        ShowBtnOpenCloseTCP(true, "关闭监听");
                    }
                    else
                    {
                        MessageBox.Show("开启监听失败！", "提示");
                    }
                }
                else  // 关闭监听
                {
                    _HPSocket_TCPServerHelper.Stop();
                    _HPSocket_TCPServerHelper._server.OnAccept -= OnAccept;                // TCP连接准备事件-使用附加数据处理黏包
                    _HPSocket_TCPServerHelper._server.OnHandShake -= OnHandShake;          // TCP握手成功事件
                    _HPSocket_TCPServerHelper._server.OnPrepareListen -= OnPrepareListen;  // 监听事件
                    _HPSocket_TCPServerHelper._server.OnSend -= OnSend;                    // 数据包发送事件
                    _HPSocket_TCPServerHelper._server.OnReceive -= OnReceive;              // 数据包接收事件
                    _HPSocket_TCPServerHelper._server.OnClose -= OnClose;                  // TCP连接关闭事件
                    _HPSocket_TCPServerHelper._server.OnShutdown -= OnShutdown;            // TCP服务器关闭事件

                    ShowBtnOpenCloseTCP(false, "开启监听");
                }
            }
            catch (Exception ex)
            {
                ShowBtnOpenCloseTCP(false, "开启监听");
                ShowLog($"开启/关闭监听失败，错误信息: {ex.Message}");
            }
        }

        /// <summary>
        /// 广播按钮
        /// </summary>
        private async void btnSendMsg_Click(object sender, EventArgs e)
        {
            try
            {
                // 检查地址
                if (!CheckServerUrl())
                {
                    return;
                }

                string hostname = txtIPAddress.Text;
                int port = int.Parse(txtPort.Text);
                string sendMsg = txtMsg.Text;  // 
                if (string.IsNullOrEmpty(sendMsg))
                {
                    ShowLog("发送信息不可为空！");
                    return;
                }

                byte[] bytes = System.Text.Encoding.UTF8.GetBytes(sendMsg + _endsWith);
                int length = bytes.Length;

                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.AppendLine(string.Concat("TCPServer服务器广播了内容：“", sendMsg, "”"));

                List<IntPtr> connIds = _HPSocket_TCPServerHelper.GetAllConnectionIds();
                stringBuilder.AppendLine($"  客户端个数为{connIds.Count}；客户端接收结果如下：");
                foreach (IntPtr connId in connIds)
                {
                    try
                    {
                        if (!_HPSocket_TCPServerHelper.GetLocalAddress(connId, out string ip, out ushort port1))
                        {
                            stringBuilder.AppendLine(string.Concat($"    客户端[{connId}]", ",接收结果：失败！连接已断开！"));
                            continue;
                        }
                        bool resultData_TCP = _HPSocket_TCPServerHelper.Send(connId, bytes, length);  // 连接并发送
                        //stringBuilder.AppendLine(string.Concat($"    客户端[{connId}]{ip}:{port1}", ",接收结果：", resultData_TCP, "_", $"[{_HPSocket_TCPServerHelper._server.ErrorCode}]", _HPSocket_TCPServerHelper._server.ErrorMessage));
                    }
                    catch (Exception ex)
                    {
                        stringBuilder.AppendLine(string.Concat($"    客户端[{connId}]", ",接收结果：失败！ 错误信息：", ex.Message));
                    }
                }
                ShowLog(stringBuilder.ToString());
            }
            catch (Exception ex)
            {
                ShowLog("TCPServer服务器广播内容中止！错误信息：" + ex.Message);
            }
        }

        #region TCP事件
        /// <summary>
        /// TCP连接事件（连接前）-使用附加数据处理黏包，不可异步
        /// </summary>
        /// <param name="sender">服务器对象</param>
        /// <param name="connId">连接ID</param>
        /// <param name="client">如果为 TCP 连接，pClient为 SOCKET 句柄；如果为 UDP 连接，pClient为 SOCKADDR 指针；</param>
        /// <returns></returns>
        private HandleResult OnAccept(IServer sender, IntPtr connId, IntPtr client)
        {
            // 获取客户端地址
            if (!sender.GetRemoteAddress(connId, out string ip, out ushort port))
            {
                return HandleResult.Error;
            }

            // 设置附加数据（用来做粘包处理）
            sender.SetExtra(connId, string.Empty);  // 初始化附加信息

            ShowLog(string.Format("TCP客户端接入({0}), ip: {1}, port: {2}", connId, ip, port));
            return HandleResult.Ok;
        }

        /// <summary>
        /// TCP握手成功事件
        /// </summary>
        /// <param name="sender">服务器对象</param>
        /// <param name="connId">连接ID</param>
        /// <returns></returns>
        private HandleResult OnHandShake(IServer sender, IntPtr connId)
        {
            // 一般用不到
            return HandleResult.Ok;
        }

        /// <summary>
        /// 监听事件
        /// </summary>
        /// <param name="server">服务器对象</param>
        /// <param name="intPtr">连接ID</param>
        /// <returns></returns>
        private HandleResult OnPrepareListen(IServer server, IntPtr intPtr)
        {
            ShowLog(string.Format("TCP服务器开启监听({0}:{1}), listen:{2}", server.Address, server.Port, intPtr));
            return HandleResult.Ok;
        }

        /// <summary>
        /// 数据包发送事件
        /// </summary>
        /// <param name="sender">服务器对象</param>
        /// <param name="connId">连接ID</param>
        /// <param name="data">数据包</param>
        /// <returns></returns>
        private HandleResult OnSend(IServer sender, IntPtr connId, byte[] data)
        {
            sender.GetRemoteAddress(connId, out string ip, out ushort port);  // 获取客户端地址

            ShowLog(string.Format("TCP服务器发送数据[ID:{0},客户端地址：‘{1}:{2}’];数据[长度{3}]：{4}", connId, ip ?? "未找到IP", port, data.Length, Encoding.UTF8.GetString(data)));
            return HandleResult.Ok;
        }

        /// <summary>
        /// 数据包接收事件
        /// </summary>
        /// <param name="sender">服务器对象</param>
        /// <param name="connId">连接ID</param>
        /// <param name="data">数据包</param>
        /// <returns></returns>
        private HandleResult OnReceive(IServer sender, IntPtr connId, byte[] data)
        {
            // <1> 获取客户端地址
            if (!sender.GetRemoteAddress(connId, out string ip, out ushort port))
            {
                return HandleResult.Error;
            }
            // <2> 获取附加数据对象
            var extraDataStr = sender.GetExtra<string>(connId);
            if (extraDataStr == null)
            {
                return HandleResult.Error;
            }
            // <3> 将接收数据转换成字符串
            string msg = Encoding.UTF8.GetString(data);
            extraDataStr += msg;  // 添加数据到缓存_不合格的数据添加到缓存区（用于粘包、拆包）

            // <4> 显示信息
            ShowLog(string.Format("TCP服务器接收客户端[ID:{0},IP:‘{1}:{2}’]的信息;数据:[长度{3}]: {4}", connId, ip, port, data.Length, msg));

            // <5> 处理数据
            HandleResult result;
            while (true)
            {
                int index = extraDataStr.IndexOf(_endsWith);
                if (index == -1) // 数据接收不完整，忽略后等待下一次接收
                {
                    result = HandleResult.Ignore;
                    break;
                }
                else
                {
                    string validMsg = extraDataStr.Remove(0, index);
                    // <6> 业务处理-异步(validMsg内容解析时的格式校验属于业务范畴)

                    // <7> 移除已取出数据
                    extraDataStr = extraDataStr.Remove(0, index + _endsWith.Length);
                }
            }

            // <8> 保存PacketData数据
            if (extraDataStr.Length > _HPSocket_TCPServerHelper.SocketBufferSize)  // 可选-控制长度为4096(注：实际所占空间大小>4096)
            {
                int length_Delete = extraDataStr.Length - Convert.ToInt32(_HPSocket_TCPServerHelper.SocketBufferSize);
                extraDataStr = extraDataStr.Remove(0, length_Delete);  // 清除长度超标数据
            }
            sender.SetExtra(connId, extraDataStr);  // 初始化附加信息

            return result;
        }

        /// <summary>
        /// TCP连接关闭事件
        /// </summary>
        /// <param name="sender">服务器对象</param>
        /// <param name="connId">连接ID</param>
        /// <param name="socketOperation">关闭的类型</param>
        /// <param name="errorCode">错误时的错误代码</param>
        /// <returns></returns>
        private HandleResult OnClose(IServer sender, IntPtr connId, SocketOperation socketOperation, int errorCode)
        {
            // <1> 获取客户端地址
            if (!sender.GetRemoteAddress(connId, out string ip, out ushort port))
            {
                return HandleResult.Ignore;
            }
            // <2> 释放附加数据
            if (sender.GetExtra<string>(connId) != null)
            {
                sender.RemoveExtra(connId);  // 删除附加数据
            }
            // <3> 显示信息
            ShowLog(string.Format("TCP客户端连接断开(ID {0},地址 {1}:{2}), 断开类型: {3},错误代码: {4}", connId, ip, port, socketOperation.ToString(), errorCode));

            return HandleResult.Ok;
        }

        /// <summary>
        /// TCP服务器关闭事件
        /// </summary>
        /// <param name="sender">服务器对象</param>
        /// <returns></returns>
        private HandleResult OnShutdown(IServer sender)
        {
            ShowLog(string.Format("TCP服务器关闭({0}:{1})", sender.Address, sender.Port));
            return HandleResult.Ok;
        }
        #endregion TCP事件

        #region 方法
        /// <summary>
        /// 检查连接是否正常
        /// </summary>
        /// <returns>true为通过</returns>
        private bool CheckServerUrl()
        {
            if (string.IsNullOrEmpty(txtIPAddress.Text))  // 
            {
                ShowLog("发送信息不可为空！");
                return false;
            }
            if (string.IsNullOrEmpty(txtPort.Text))  // 
            {
                ShowLog("端口不可为空！");
                return false;
            }
            return true;
        }
        #endregion 方法

        #region 操控页面控件
        /// <summary>
        /// 开关按钮刷新
        /// </summary>
        /// <param name="msg">信息</param>
        public void ShowBtnOpenCloseTCP(bool isSuccess, string text)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action<bool, string>(ShowBtnOpenCloseTCP), isSuccess, text);
                return;
            }

            btnOpenCloseTCP.BackColor = isSuccess ? Color.FromArgb(128, 255, 128) : Color.FromArgb(255, 128, 128);
            btnOpenCloseTCP.Text = text;  // isSuccess? "关闭监听-控制线程" : "开启监听-控制线程";
        }

        /// <summary>
        /// 显示信息
        /// </summary>
        /// <param name="msg">信息</param>
        public void ShowLog(string msg)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action<string>(ShowLog), msg);
                return;
            }

            if (rTxtInfo.Text.Length > 2000)
            {
                rTxtInfo.Text = string.Empty;
            }
            rTxtInfo.AppendText(string.Concat("\r\n", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "->", msg));
        }
        #endregion 操控页面控件
    }
}
